<?php
/**
 * 图片、文件上传类
 * User: dxk
 * Date: 2020/07/17
 */

namespace App\Library\Service;

use App\Library\Service\AliCloud\OSS;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class Upload
{
    private $max_file_size = 0;
    private $allow_extension = [];
    private bool $is_upload_cloud = false;//是否上传到云空间
    private bool $is_thumb_pic = true;//是否压缩图片

    /**
     * 设置文件大小
     * @param string $max_file_size 100000、2K、3M
     * @return upload
     */
    public function setMaxFileSize(string $max_file_size): Upload
    {
        $max_file_size = strtolower(trim($max_file_size));
        if (\Str::endsWith($max_file_size, 'k')) {
            $max_file_size = rtrim($max_file_size, 'k');
            if (!is_numeric($max_file_size)) {
                return $this;
            }
            $max_file_size = $max_file_size * 1024;
        }
        if (\Str::endsWith($max_file_size, 'm')) {
            $max_file_size = rtrim($max_file_size, 'm');
            if (!is_numeric($max_file_size)) {
                return $this;
            }
            $max_file_size = $max_file_size * 1024 * 1024;
        }
        $this->max_file_size = $max_file_size;
        return $this;
    }

    /**
     * 是否上传到云空间
     * @param $is_upload_cloud
     * @return $this
     */
    public function setIsUploadCloud($is_upload_cloud): Upload
    {
        $this->is_upload_cloud = (bool)$is_upload_cloud;
        return $this;
    }

    /**
     * 是否缩略图
     * @param $is_thumb_pic
     * @return $this
     */
    public function setIsThumbPic($is_thumb_pic): Upload
    {
        $this->is_thumb_pic = (bool)$is_thumb_pic;
        return $this;
    }

    /**
     * 设置允许的扩展类型
     *
     * @param array $allow_extension
     * @return upload
     */
    public function setAllowExtension(array $allow_extension): Upload
    {
        $this->allow_extension = $allow_extension;
        return $this;
    }

    /**
     * 字节转换
     * @param $size
     * @return string
     */
    private function formatBytes($size): string
    {
        $units = array(' B', ' KB', ' MB', ' GB', ' TB');
        for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
        return round($size, 2) . $units[$i];
    }

    /**
     * 上传文件
     * @param UploadedFile $file
     * @param $dst_dir
     * @param bool $is_storage_dir
     * @return array
     */
    public function uploadFile(UploadedFile $file, $dst_dir, bool $is_storage_dir = false): array
    {
        if (empty($this->allow_extension)) {
            $this->allow_extension = config('sys.allow_file_type');
        }
        if (empty($this->max_file_size)) {
            self::setMaxFileSize('10M');
        }
        if (!$file->isValid()) {
            return alert_info(1, $file->getErrorMessage());
        }
        $extension = strtolower($file->getClientOriginalExtension());
        if (!$extension || !in_array($extension, $this->allow_extension)) {
            return alert_info(1, '不支持的文件类型');
        }
        $file_size = $file->getSize();
        if ($file_size > $this->max_file_size) {
            return alert_info(1, '文件大小超过限制,最大允许' . self::formatBytes($this->max_file_size));
        }
        //创建目录
        if ($is_storage_dir) {
            $dir_info = $this->getStorageDir($file, $dst_dir);
        } else {
            $dir_info = $this->getAttachDir($dst_dir);
        }
        if (!is_array($dir_info)) {
            return alert_info(1, '目录创建失败');
        }
        $file_name = $dir_info['file_name'] . '.' . $extension;
        $store_name = $dir_info['store_path'] . $file_name;
        $file_path = $dir_info['file_path'];
        //上传文件
        try {
            $file->move($file_path, $file_name);
        } catch (\Exception $e) {
            return alert_info(1, $e->getMessage());
        }
        $file_path .= $file_name;
        //超过100KB 压缩图片
        if (in_array(strtolower($extension), ['png', 'jpg', 'jpeg']) && $this->is_thumb_pic && $file_size > 100 * 1024) {
            $thumpPic = new ThumbPic();
            $pic_path = $thumpPic->makeAutoThump($file_path . '_1000x30000.jpg');
            if ($pic_path !== false) {
                @unlink($file_path);
                @rename($pic_path, $file_path);
            }
        }
        if ($this->is_upload_cloud) {
            $OSS = new OSS();
            $res = $OSS->uploadFile(str_replace('\\', '/', $store_name), file_get_contents($file_path));
            @unlink($file_path);
            if ($res['code'] !== 0) {
                return $res;
            }
        }
        $data = ['file_name' => $file_name, 'store_name' => $store_name, 'real_path' => $file_path, 'extension' => $extension];
        return alert_info(0, 'OK', $data);
    }

    /**
     * 上传图片
     * @param UploadedFile $file
     * @param $dst_dir
     * @return array
     */
    public function uploadImage(UploadedFile $file, $dst_dir): array
    {
        if (empty($this->allow_extension)) {
            $this->allow_extension = config('sys.allow_img_type');
        }
        if (empty($this->max_file_size)) {
            self::setMaxFileSize('2M');
        }
        if (!$file->isValid()) {
            return alert_info(1, '无效图片');
        }
        $extension = strtolower($file->getClientOriginalExtension());
        if (!$extension || !in_array($extension, $this->allow_extension)) {
            return alert_info(1, '不支持的图片类型');
        }
        $file_size = $file->getSize();
        if ($file_size > $this->max_file_size) {
            return alert_info(1, '图片大小超过限制,最大允许' . self::formatBytes($this->max_file_size));
        }
        //创建目录
        $dir_info = $this->getAttachDir($dst_dir);
        if (!is_array($dir_info)) {
            return alert_info(1, '目录创建失败');
        }
        $file_name = $dir_info['file_name'] . '.' . $extension;
        $store_name = $dir_info['store_path'] . $file_name;
        $file_path = $dir_info['file_path'];
        //上传文件
        try {
            $file->move($file_path, $file_name);
        } catch (\Exception $e) {
            return alert_info(1, $e->getMessage());
        }
        $file_path .= $file_name;
        //超过100KB 压缩图片
        if (in_array(strtolower($extension), ['png', 'jpg', 'jpeg']) && $this->is_thumb_pic && $file_size > 100 * 1024) {
            $thumpPic = new ThumbPic();
            $pic_path = $thumpPic->makeAutoThump($file_path . '_1000x30000.jpg');
            if ($pic_path) {
                @unlink($file_path);
                @rename($pic_path, $file_path);
            }
        }
        if ($this->is_upload_cloud) {
            $OSS = new OSS();
            $res = $OSS->uploadFile(str_replace('\\', '/', $store_name), file_get_contents($file_path));
            @unlink($file_path);
            if ($res['code'] !== 0) {
                return $res;
            }
        }
        $data = ['file_name' => $file_name, 'store_name' => $store_name, 'src' => $this->is_upload_cloud ? easy_cloud_attached($store_name) : easy_attached($store_name), 'real_path' => $file_path, 'extension' => $extension];
        return alert_info(0, 'OK', $data);
    }

    /**
     * 创建目标上传目录
     * @param $dst_dir
     * @param bool|int $is_storage_path
     * @return array|false
     */
    public function getAttachDir($dst_dir, bool|int $is_storage_path = false): bool|array
    {
        $dst_dir = trim($dst_dir);
        $dst_dir = trim($dst_dir, '\/\\');
        $time = time();
        $file_name = strtolower(md5($time . '_' . easy_random(10)));
        $store_path = $dst_dir . DIRECTORY_SEPARATOR . date('Ym') . DIRECTORY_SEPARATOR;
        $store_path .= substr($file_name, 0, 2) . DIRECTORY_SEPARATOR;
        if ($is_storage_path) {
            $file_path = storage_path($store_path);
        } else {
            $file_path = easy_attached_path($store_path);
        }
        if (!is_dir($file_path)) {
            $res = easy_mk_dir($file_path);
            if (!$res) {
                return false;
            }
        }
        return ['store_path' => $store_path, 'file_name' => $file_name, 'file_path' => $file_path];
    }

    /**
     * 创建目标上传目录2
     * @param $file
     * @param $dst_dir
     * @return array|bool
     */
    public function getStorageDir($file, $dst_dir): bool|array
    {
        //原文件名
        $file_name = current(explode('.', $file->getClientOriginalName()));
        if (!is_dir($dst_dir)) {
            $res = easy_mk_dir($dst_dir);
            if (!$res) {
                return false;
            }
        }
        return ['store_path' => $dst_dir, 'file_name' => $file_name, 'file_path' => $dst_dir];
    }

    /**
     * 上传图片到云端
     * @param $image_file
     * @param $is_thumb_pic
     * @param $dst_dir
     * @return array
     */
    public function fileToCloud($image_file, $is_thumb_pic = true, $dst_dir = 'cookbook_import')
    {
        if (empty($image_file)) {
            return alert_info(1, '路径错误！');
        }
        if (!is_file($image_file)) {
            return alert_info(1, '文件不存在！');
        }
        $file = new File($image_file);
        $extension = $file->getExtension();
        $extension = strtolower($extension);
        if (!in_array($extension, ['png', 'jpg', 'jpeg', 'mp4'])) {
            return alert_info(1, '不支持的文件！');
        }
        $file_size = $file->getSize();

        //创建目录
        $dir_info = $this->getAttachDir($dst_dir);
        if (!is_array($dir_info)) {
            return alert_info(1, '目录创建失败');
        }
        $file_name = $dir_info['file_name'] . '.' . $extension;
        $store_name = $dir_info['store_path'] . $file_name;
        $file_path = $dir_info['file_path'];
        //上传文件
        try {
            $file->move($file_path, $file_name);
        } catch (\Exception $e) {
            return alert_info(1, $e->getMessage());
        }
        $file_path .= $file_name;
        //超过100KB 压缩图片
        if (in_array(strtolower($extension), ['png', 'jpg', 'jpeg']) && $is_thumb_pic && $file_size > 100 * 1024) {
            $thumpPic = new ThumbPic();
            $pic_path = $thumpPic->makeAutoThump($file_path . '_1000x30000.jpg');
            if ($pic_path) {
                @unlink($file_path);
                @rename($pic_path, $file_path);
            }
        }
        $OSS = new OSS();
        $res = $OSS->uploadFile(str_replace('\\', '/', $store_name), file_get_contents($file_path));
        @unlink($file_path);
        if ($res['code'] !== 0) {
            return $res;
        }
        $data = ['file_name' => $file_name, 'store_name' => $store_name, 'real_path' => $file_path, 'extension' => $extension];
        return alert_info(0, 'OK', $data);
    }
}
